#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "common/console.h"
#include "common/socket_udp.h"
#include "userLog.h"

static CONSOLE_CMD_NODE_S gsConsoleCmdList[CONSOLE_CMD_MAX];

static int gsnConsoleLoopRun = 1;

console_msg_declare(console);

CONSOLE_CMD_NODE_S *Console_CmdSearch(char *pCmd);

int Console_Loop(uv_work_t *handle)
{
	int nRet = 0;
	int nSock = -1;
	SOCKET_UDP_SECTION_S stSection;
	char abyCmdRetBuf[16 * 1024];
	int nLen = 0;
	CONSOLE_CMD_PARAM_S stCmdParam;
	CONSOLE_CMD_NODE_S *pCmdNode = NULL;

	nSock = SocketUdpCreateServer("127.0.0.1", CONSOLE_UDP_PORT);
	if (nSock < 0)
	{
		LOG_ERROR("Console udp server error");
		return -1;
	}

	stSection.nSocket = nSock;

	while (gsnConsoleLoopRun)
	{
		memset(abyCmdRetBuf, 0, sizeof(abyCmdRetBuf));
		// recv cmd
		nRet = SocketUdpRecv(&stSection, &stCmdParam, sizeof(stCmdParam));
		if (nRet < 0)
		{
			LOG_ERROR("console SocketUdpRecv() error");
			goto _error;
		}

		// exe cmd here
		LOG_INFO("cmd:%s, args num:%d", stCmdParam.abyCmd, stCmdParam.nArgsNum);
		int i;
		for (i = 0; i < stCmdParam.nArgsNum; i++)
		{
			LOG_INFO("args[%d]:%s", i, stCmdParam.abyArgs[i]);
		}
		pCmdNode = Console_CmdSearch(stCmdParam.abyCmd);
		if (pCmdNode)
		{
			sprintf(abyCmdRetBuf, "cmd ok!\n");
			if (pCmdNode->cb)
			{
				pCmdNode->cb(&stCmdParam, abyCmdRetBuf);
			}
		}
		else
		{
			sprintf(abyCmdRetBuf, "Console CMD, can not found cmd:%s\n", stCmdParam.abyCmd);
		}
		// send result back
		LOG_INFO("send back:%s", abyCmdRetBuf);
		LOG_INFO("ip:%s, port:%d", stSection.abyRemoteIp, stSection.nRemotePort);
		nRet = SocketUdpSend(&stSection, abyCmdRetBuf, strlen(abyCmdRetBuf));
		LOG_INFO("nRet:%d", nRet);
	}

	return 0;

_error:
	SocketUdpDestroyServer(nSock);
	return -1;
}

int Console_CmdAdd(char *pCmd, CONSOLE_CMD_CB cb)
{
	int i;
	char link[128] = {0};

	if (pCmd == NULL)
	{
		LOG_ERROR("cmd is null!");
		return -1;
	}

	if (strlen(pCmd) >= sizeof(gsConsoleCmdList[0].abyCmd))
	{
		LOG_ERROR("cmd too long:%s", pCmd);
		return -1;
	}

	for (i = 0; i < CONSOLE_CMD_MAX; i++)
	{
		if (gsConsoleCmdList[i].nUsed == 0)
		{
			strcpy(gsConsoleCmdList[i].abyCmd, pCmd);
			gsConsoleCmdList[i].cb = cb;
			gsConsoleCmdList[i].nUsed = 1;
			sprintf(link, CONSOLE_CMD_ROOT "/%s", pCmd);
			unlink(link);
			symlink(CONSOLE_HOME "/console_cmd", link);
			LOG_INFO("console cmd add %s ok!", pCmd);
			return 0;
		}
	}

	LOG_ERROR("cmd too more!");

	return -1;
}

int Console_CmdDel(char *pCmd)
{
}

CONSOLE_CMD_NODE_S *Console_CmdSearch(char *pCmd)
{
	int i;
	CONSOLE_CMD_NODE_S *pNode = NULL;

	if (pCmd == NULL)
	{
		LOG_ERROR("invalid args");
		return NULL;
	}

	for (i = 0; i < CONSOLE_CMD_MAX; i++)
	{
		if (strcmp(pCmd, gsConsoleCmdList[i].abyCmd) == 0)
		{
			pNode = &gsConsoleCmdList[i];
			return pNode;
		}
	}

	LOG_ERROR("can not found cmd:%s", pCmd);
	return NULL;
}

static int Console_CmdSysQuit(CONSOLE_CMD_PARAM_S *pParam, char *pAck)
{
	char abyHelp[] = "./cmd 1 for quit, 0 for test";
	int nParam = 0;

	if (pParam == NULL || pAck == NULL)
	{
		return -1;
	}

	if (pParam->nArgsNum != 1)
	{
		sprintf(pAck, "%s", abyHelp);
		return 0;
	}

	nParam = strtoul(pParam->abyArgs[0], NULL, 0);
	LOG_INFO("nParam:%d", nParam);

	if (nParam == 0)
	{
		sprintf(pAck, "for test");
		return 0;
	}

	gsnConsoleLoopRun = 0;

	sprintf(pAck, "ok");

	return 0;
}

int Console_Debug_DUP2(CONSOLE_CMD_PARAM_S *pParam, char *pAck)
{
	int nFd = -1;
	LOG_INFO("Current tty:%s ", pParam->abyArgs[15]);

	nFd = open(pParam->abyArgs[15], O_RDWR | S_IREAD | S_IWRITE);
	dup2(nFd, 1);
	close(nFd);
	LOG_INFO("%s success", __FUNCTION__);

	return 0;
}

int Console_Init(void)
{
	memset(gsConsoleCmdList, 0, sizeof(CONSOLE_CMD_NODE_S) * CONSOLE_CMD_MAX);

	console_level(console, 0);

	Console_CmdAdd("t-quit", Console_CmdSysQuit);
	Console_CmdAdd("t-console_dup2", Console_Debug_DUP2);

	return 0;
}

int Console_DeInit(void)
{
}
